﻿// Decompiled with JetBrains decompiler
// Type: Netick.CodeGen.WeaverUtils
// Assembly: Netick.CodeGen, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 95965C71-875F-44B8-BA79-93A19C7D6A17
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Editor\Netick.CodeGen.dll

using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using Mono.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;

#nullable disable
namespace Netick.CodeGen;

public static class WeaverUtils
{
  private static Dictionary<string, int> Primitives = new Dictionary<string, int>(14)
  {
    {
      "Byte",
      1
    },
    {
      "SByte",
      1
    },
    {
      "Boolean",
      1
    },
    {
      "Int16",
      2
    },
    {
      "UInt16",
      2
    },
    {
      "Char",
      2
    },
    {
      "Int32",
      4
    },
    {
      "UInt32",
      4
    },
    {
      "Single",
      4
    },
    {
      "Int64",
      8
    },
    {
      "UInt64",
      8
    },
    {
      "Double",
      8
    },
    {
      "Guid",
      16 /*0x10*/
    },
    {
      "Decimal",
      16 /*0x10*/
    },
    {
      "IntPtr",
      8
    },
    {
      "UIntPtr",
      8
    }
  };

  public static TypeReference MakeGenericType(
    this TypeReference self,
    params TypeReference[] arguments)
  {
    if (self.GenericParameters.Count != arguments.Length)
      throw new ArgumentException();
    GenericInstanceType genericInstanceType = new GenericInstanceType(self);
    foreach (TypeReference typeReference in arguments)
      genericInstanceType.GenericArguments.Add(typeReference);
    return (TypeReference) genericInstanceType;
  }

  public static MethodReference MakeGeneric(
    this MethodReference self,
    params TypeReference[] arguments)
  {
    MethodReference methodReference1 = new MethodReference(((MemberReference) self).Name, self.ReturnType);
    ((MemberReference) methodReference1).DeclaringType = ((MemberReference) self).DeclaringType.MakeGenericType(arguments);
    methodReference1.HasThis = self.HasThis;
    methodReference1.ExplicitThis = self.ExplicitThis;
    methodReference1.CallingConvention = self.CallingConvention;
    MethodReference methodReference2 = methodReference1;
    foreach (ParameterDefinition parameter in self.Parameters)
      methodReference2.Parameters.Add(new ParameterDefinition(((ParameterReference) parameter).ParameterType));
    foreach (GenericParameter genericParameter in self.GenericParameters)
      methodReference2.GenericParameters.Add(new GenericParameter(((MemberReference) genericParameter).Name, (IGenericParameterProvider) methodReference2));
    return methodReference2;
  }

  private static MethodDefinition GetStaticConstructor(TypeDefinition typeDefinition)
  {
    MethodDefinition staticConstructor = TypeDefinitionRocks.GetStaticConstructor(typeDefinition);
    if (staticConstructor == null)
    {
      staticConstructor = new MethodDefinition(".cctor", (MethodAttributes) 6288, ((MemberReference) typeDefinition).Module.TypeSystem.Void);
      staticConstructor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
      typeDefinition.Methods.Add(staticConstructor);
    }
    return staticConstructor;
  }

  public static bool IsSubclassOf(this TypeDefinition typeDefinition, string ClassTypeFullName)
  {
    if (!typeDefinition.IsClass)
      return false;
    for (TypeReference baseType = typeDefinition.BaseType; baseType != null; baseType = baseType.Resolve().BaseType)
    {
      if (((MemberReference) baseType).FullName == ClassTypeFullName)
        return true;
      if (baseType.Resolve() == null)
        return false;
    }
    return false;
  }

  public static bool HasInterface(this TypeReference typeReference, string InterfaceTypeFullName)
  {
    if (typeReference.IsArray)
      return false;
    try
    {
      return ((IEnumerable<InterfaceImplementation>) typeReference.Resolve().Interfaces).Any<InterfaceImplementation>((Func<InterfaceImplementation, bool>) (iface => ((MemberReference) iface.InterfaceType).FullName == InterfaceTypeFullName));
    }
    catch
    {
      return false;
    }
  }

  public static MethodReference MakeGenericMethodReference(
    this MethodReference method,
    TypeDefinition def)
  {
    MethodReference methodReference = method;
    GenericInstanceType genericInstanceType = new GenericInstanceType(((MemberReference) method).DeclaringType);
    foreach (GenericParameter genericParameter in ((MemberReference) method).DeclaringType.GenericParameters)
      genericInstanceType.GenericArguments.Add((TypeReference) genericParameter);
    method = new MethodReference(((MemberReference) method).Name, method.ReturnType, (TypeReference) genericInstanceType)
    {
      HasThis = method.HasThis,
      ExplicitThis = method.ExplicitThis,
      CallingConvention = method.CallingConvention
    };
    foreach (ParameterDefinition parameter in methodReference.Parameters)
      method.Parameters.Add(parameter);
    return method;
  }

  public static MethodReference MakeGeneric2(MethodReference method, params TypeReference[] args)
  {
    if (args.Length == 0)
      return method;
    if (method.GenericParameters.Count != args.Length)
      throw new ArgumentException("Invalid number of generic typearguments supplied");
    GenericInstanceMethod genericInstanceMethod = new GenericInstanceMethod(method);
    foreach (TypeReference typeReference in args)
      genericInstanceMethod.GenericArguments.Add(typeReference);
    return (MethodReference) genericInstanceMethod;
  }

  private static MethodReference MakeGeneric3(MethodReference method, params TypeReference[] args)
  {
    if (args.Length == 0)
      return method;
    if (method.GenericParameters.Count != args.Length)
      throw new ArgumentException("Invalid number of generic typearguments supplied");
    GenericInstanceMethod genericInstanceMethod = new GenericInstanceMethod(method);
    foreach (TypeReference typeReference in args)
      genericInstanceMethod.GenericArguments.Add(typeReference);
    return (MethodReference) genericInstanceMethod;
  }

  public static string GetMethodName(MethodDefinition method)
  {
    string methodName = ((MemberReference) method.DeclaringType).FullName + ((MemberReference) method).Name;
    Collection<ParameterDefinition> parameters = ((MethodReference) method).Parameters;
    for (int index = 0; index < parameters.Count; ++index)
      methodName += ((MemberReference) ((ParameterReference) parameters[index]).ParameterType).Name;
    return methodName;
  }

  public static MethodDefinition FindMethod(string name, TypeDefinition typeDef)
  {
    return ((IEnumerable<MethodDefinition>) typeDef.Methods).Where<MethodDefinition>((Func<MethodDefinition, bool>) (m => ((MemberReference) m).Name == name)).FirstOrDefault<MethodDefinition>();
  }

  public static MethodReference MakeGenericMethod_CORRECT(
    MethodReference method,
    TypeReference type,
    TypeReference openType,
    out GenericInstanceType genericNewType)
  {
    genericNewType = TypeReferenceRocks.MakeGenericInstanceType(openType, new TypeReference[1]
    {
      type
    });
    MethodReference methodReference1 = new MethodReference(((MemberReference) method).Name, method.ReturnType);
    methodReference1.HasThis = method.HasThis;
    methodReference1.ExplicitThis = method.ExplicitThis;
    ((MemberReference) methodReference1).DeclaringType = (TypeReference) genericNewType;
    methodReference1.CallingConvention = method.CallingConvention;
    MethodReference methodReference2 = methodReference1;
    foreach (ParameterDefinition parameter in method.Parameters)
      methodReference2.Parameters.Add(new ParameterDefinition(((ParameterReference) parameter).Name, parameter.Attributes, ((ParameterReference) parameter).ParameterType));
    return methodReference2;
  }

  private static SizeOfData SizeOfEnum(TypeDefinition type, ICodeGenUser gameEngineCodeGen)
  {
    foreach (FieldDefinition field in type.Fields)
    {
      if (!field.IsStatic)
        return WeaverUtils.SizeOfInternal(((FieldReference) field).FieldType, (Dictionary<TypeReference, TypeReference>) null, gameEngineCodeGen);
    }
    return new SizeOfData(4, 4);
  }

  public static SizeOfData SizeOfStruct(
    TypeReference typeRef,
    Dictionary<TypeReference, TypeReference> parentParaToArg,
    ICodeGenUser gameEngineCodeGen)
  {
    TypeDefinition typeDefinition = typeRef.Resolve();
    if (typeDefinition == null)
      return new SizeOfData(4, 4);
    GenericInstanceType genericInstanceType = typeRef as GenericInstanceType;
    Dictionary<TypeReference, TypeReference> parentParaToArg1 = new Dictionary<TypeReference, TypeReference>();
    if (genericInstanceType != null)
    {
      for (int index = 0; index < genericInstanceType.GenericArguments.Count; ++index)
      {
        TypeReference typeReference;
        if (parentParaToArg != null && parentParaToArg.TryGetValue(genericInstanceType.GenericArguments[index], out typeReference))
          parentParaToArg1.Add((TypeReference) ((TypeReference) typeDefinition).GenericParameters[index], typeReference);
        else
          parentParaToArg1.Add((TypeReference) ((TypeReference) typeDefinition).GenericParameters[index], genericInstanceType.GenericArguments[index]);
      }
    }
    if (genericInstanceType != null && genericInstanceType.GenericArguments.Count != ((TypeReference) typeDefinition).GenericParameters.Count)
      gameEngineCodeGen.LogError((object) $"Mismatch {((MemberReference) typeRef).Name}    generic.GenericArguments.Count:{genericInstanceType.GenericArguments.Count}     typeRef.GenericParameters.Count{typeRef.GenericParameters.Count}");
    long size1 = 0;
    long alignment1 = 4;
    foreach (FieldDefinition field in typeDefinition.Fields)
    {
      if (!field.IsStatic)
      {
        TypeReference typeReference1 = ((FieldReference) field).FieldType;
        TypeReference typeReference2;
        if (parentParaToArg1.TryGetValue(typeReference1, out typeReference2))
          typeReference1 = typeReference2;
        SizeOfData sizeOfData = WeaverUtils.SizeOfInternal(typeReference1, parentParaToArg1, gameEngineCodeGen);
        long alignment2 = (long) sizeOfData.Alignment;
        long size2 = (long) sizeOfData.Size;
        long num1 = Math.Min(8L, alignment2);
        if (num1 > alignment1)
          alignment1 = num1;
        if (size1 % num1 == 0L)
        {
          size1 += size2;
        }
        else
        {
          long num2 = num1 - size1 % num1;
          size1 += size2 + num2;
        }
      }
    }
    if (size1 == 0L)
      return new SizeOfData(1, 1);
    if (size1 % alignment1 != 0L)
    {
      long num = alignment1 - size1 % alignment1;
      size1 += num;
    }
    return new SizeOfData((int) size1, (int) alignment1);
  }

  public static SizeOfData SizeOfInternal(
    TypeReference type,
    Dictionary<TypeReference, TypeReference> parentParaToArg,
    ICodeGenUser gameEngineCodeGen)
  {
    if (!type.IsValueType || type.IsArray)
      return new SizeOfData(8, 8);
    int num;
    if (type.Namespace == "System" && WeaverUtils.Primitives.TryGetValue(((MemberReference) type).Name, out num))
      return new SizeOfData(num, num);
    TypeDefinition type1 = type.Resolve();
    if (type1 == null)
      return new SizeOfData(4, 4);
    return type1.IsEnum ? WeaverUtils.SizeOfEnum(type1, gameEngineCodeGen) : WeaverUtils.SizeOfStruct(type, parentParaToArg, gameEngineCodeGen);
  }

  public static long SizeOf(TypeReference type, ICodeGenUser gameEngineCodeGen)
  {
    return (long) WeaverUtils.SizeOfInternal(type, (Dictionary<TypeReference, TypeReference>) null, gameEngineCodeGen).Size;
  }

  public static void ProcessGenericStruct(
    ICodeGenUser gameEngineCodeGen,
    PropertyDefinition property)
  {
    if (!((PropertyReference) property).PropertyType.IsGenericInstance)
      return;
    WeaverUtils.InternalProcessGenericStruct(gameEngineCodeGen, ((PropertyReference) property).PropertyType, (Dictionary<TypeReference, TypeReference>) null);
  }

  private static void InternalProcessGenericStruct(
    ICodeGenUser gameEngineCodeGen,
    TypeReference typeRef,
    Dictionary<TypeReference, TypeReference> parentParaToArg)
  {
  }

  public static void InsertLdind(
    TypeReference item,
    Collection<Instruction> instructions,
    ILProcessor il)
  {
    string name = ((MemberReference) item).Name;
    TypeDefinition typeDefinition = item.Resolve();
    if (typeDefinition != null && typeDefinition.IsEnum)
    {
      WeaverUtils.InsertLdind(TypeDefinitionRocks.GetEnumUnderlyingType(typeDefinition), instructions, il);
    }
    else
    {
      if (!item.IsValueType || !(item.Namespace != "System"))
      {
        switch (name)
        {
          case "Guid":
            break;
          case "Single":
            instructions.Add(il.Create(OpCodes.Ldind_R4));
            return;
          case "Double":
            instructions.Add(il.Create(OpCodes.Ldind_R8));
            return;
          case "Boolean":
            instructions.Add(il.Create(OpCodes.Ldind_U1));
            return;
          case "Int64":
          case "UInt64":
            instructions.Add(il.Create(OpCodes.Ldind_I8));
            return;
          case "Byte":
            instructions.Add(il.Create(OpCodes.Ldind_U1));
            return;
          case "SByte":
            instructions.Add(il.Create(OpCodes.Ldind_I1));
            return;
          case "Int16":
            instructions.Add(il.Create(OpCodes.Ldind_I2));
            return;
          case "UInt16":
            instructions.Add(il.Create(OpCodes.Ldind_U2));
            return;
          case "Int32":
            instructions.Add(il.Create(OpCodes.Ldind_I4));
            return;
          case "UInt32":
            instructions.Add(il.Create(OpCodes.Ldind_U4));
            return;
          default:
            instructions.Add(il.Create(OpCodes.Ldind_I4));
            return;
        }
      }
      instructions.Add(il.Create(OpCodes.Ldobj, item));
    }
  }

  public static void InsertStind(
    TypeReference item,
    List<Instruction> instructions,
    ILProcessor il)
  {
    string name = ((MemberReference) item).Name;
    TypeDefinition typeDefinition = item.Resolve();
    if (typeDefinition != null && typeDefinition.IsEnum)
    {
      WeaverUtils.InsertStind(TypeDefinitionRocks.GetEnumUnderlyingType(typeDefinition), instructions, il);
    }
    else
    {
      if (!item.IsValueType || !(item.Namespace != "System"))
      {
        switch (name)
        {
          case "Guid":
            break;
          case "Single":
            instructions.Add(il.Create(OpCodes.Stind_R4));
            return;
          case "Double":
            instructions.Add(il.Create(OpCodes.Stind_R8));
            return;
          case "Boolean":
            instructions.Add(il.Create(OpCodes.Stind_I1));
            return;
          case "Int64":
          case "UInt64":
            instructions.Add(il.Create(OpCodes.Stind_I8));
            return;
          case "Byte":
            instructions.Add(il.Create(OpCodes.Stind_I1));
            return;
          case "SByte":
            instructions.Add(il.Create(OpCodes.Stind_I1));
            return;
          case "Int16":
            instructions.Add(il.Create(OpCodes.Stind_I2));
            return;
          case "UInt16":
            instructions.Add(il.Create(OpCodes.Stind_I2));
            return;
          case "Int32":
            instructions.Add(il.Create(OpCodes.Stind_I4));
            return;
          case "UInt32":
            instructions.Add(il.Create(OpCodes.Stind_I4));
            return;
          default:
            instructions.Add(il.Create(OpCodes.Stind_I4));
            return;
        }
      }
      instructions.Add(il.Create(OpCodes.Stobj, item));
    }
  }

  public static int GetDecimals(Decimal d, int i = 0)
  {
    Decimal d1 = (Decimal) ((double) d * Math.Pow(10.0, (double) i));
    return Math.Round(d1) == d1 ? i : WeaverUtils.GetDecimals(d, i + 1);
  }
}
